import { Watcher } from "../Watcher.js"

/**
 * 编译元素节点
 * @param {*} node 元素节点 
 * @param {*} vm 实例
 */
export function compileAttribute(node, vm) {
  // 将类数组格式化的属性节点转为数组
  const attrs = Array.from(node.attributes)
  // 遍历数组
  for (let attr of attrs) {
    const { name, value } = attr
    if (name.match(/v-on:click/)) {
      // v-on指令
      compileOnClick(node, value, vm)
    } else if(name.match(/v-bind:(.*)/)) {
      // v-bind
      compileBind(node, value, vm)
    } else if(name.match(/v-model/)) {
      // v-model
      compileVModel(node, value, vm)
    }
  }
}

/**
 * 编译v-click指令
 * @param {*} node 节点 
 * @param {*} method 方法名 也就是 v-on:click = "funName"
 * @param {*} vm 实例
 */
function compileOnClick(node, method, vm) {
  // 给节点添加原生事件，回调是对应的method
  node.addEventListener('click', function(...args) {
    // 给method绑定this上下文, 执行methods中对应的方法
    vm.$options.methods[method].apply(vm, args)
  })
}

/**
 * 编译v-bind
 * @param {*} node 
 * @param {*} attrValue 
 * @param {*} vm 
 */
function compileBind(node, attrValue, vm) {
  // 属性名
  const attrName = RegExp.$1
  // 移除模板中的v-bind
  node.removeAttribute(`v-bind:${attrName}`)
  // 属性值改变时，重新执行回调函数
  function cb() {
    // 这里vm[attrValue]会出发get,使得Dep.target有值
    node.setAttribute(attrName, vm[attrValue])
  }
  // 实例化Watcher，当属性值改变时，dep通知watcher 执行update方法（其实就是执行cb）, 重新更新属性
  new Watcher(cb)
}

/**
 * 编译v-model
 * @param {*} node 
 * @param {*} key 
 * @param {*} vm 
 */
function compileVModel(node, key, vm) {
  // 先获取当前节点标签名，类型
  let { tagName, type } = node
  // 标签名转为小写
  tagName = tagName.toLowerCase()
  if (tagName === 'input' && type === 'text') {
    // <input type="text" v-model="inputVal"></input>
    // 设置input值
    node.value = vm[key]
    // 添加原生input事件，事件发生时同步修改响应式数据
    node.addEventListener('input', function() {
      vm[key] = node.value
    })
  } else if(tagName === 'input' && type === 'checkbox') {
    // 设置初始值
    node.checked = vm[key]
    // 添加原生事件
    node.addEventListener('change', function() {
      vm[key] = node.checked
    })
  }else if (tagName === 'select') {
    // <select v-model="selectVal"></select>
    // 设置初始值
    node.value = vm[key]
    // 添加原生事件
    node.addEventListener('change', function() {
      vm[key] = node.value
    })
  }
}